﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////

#include <map>
#include <string>

#include "CommandParameters.h"
#include "ICommandManager.h"
#include "AppService.h"
#include "IParameterDefinition.h"
#include "IParameterDefinitionLibrary.h"
#include "UniIdentity.h"
#include "ParameterType.h"

#include "IGmepGcsProjectManager.h"
#include "GmepVersionUtils.h"
#include "GmepUnitUtils.h"
#include "IUnitConverterManager.h"
#include "IGmepCategoryInfoUtils.h"
#include "IParameterValueStorage.h"
#include "BaseCommonUtils.h"
#include "BaseInteractionUtils.h"

#include "GmepCategoryInfo.h"
//gcs
#include "IGcsViewOptions.h"
#include "IComponentConsumeDataProvider.h"
#include "EMessageType.h"
#include "MessageAction.h"
#include "IComponentDto.h"

#include "ComponentData.h"
#include "ProjectLocalComponentService.h"
#include "ProjectLoadedComponentService.h"
#include "ProjectCloudComponentService.h"
#include "GmepLocalComponentOpertions.h"
#include "UIService.h"
#include "ComponentSqlUtils.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h" 

namespace
{
    /// \brief 重复选项枚举
    enum class EDuplicateChoice : int32_t 
    {
        Invalid = -1,   ///< 非法
        Cancel = 0,     ///< 取消
        Skip = 1,       ///< 跳过
        Continue = 2    ///< 继续
    };
    
    /// \brief 弹出重复提示，让用户选择
    EDuplicateChoice PopUpDuplicateWarning(gcs::IGcsViewOptions* pViewService, bool forSingleComponentMessage)
    {
        DBG_WARN_AND_RETURN_UNLESS(pViewService != nullptr, EDuplicateChoice::Invalid, L"pViewService为空", L"GMEP", L"2024-01-30");
        std::wstring strMessage;
        if (forSingleComponentMessage)
            strMessage = GBMP_TR(L"项目中1个构件已存在，再次添加会被另存为副本");
        else
            strMessage = GBMP_TR(L"项目中有构件已存在，再次添加会被另存为副本");

        // messageBox, 取消，跳过，还是存为副本 （1）
        gcs::MessageAction cancelAction(L"Cancel"); cancelAction.DisplayText = GBMP_TR(L"取消"); cancelAction.IsSolid = false;
        gcs::MessageAction skipAction(L"Skip"); skipAction.DisplayText = GBMP_TR(L"跳过重复构件"); skipAction.IsSolid = false; skipAction.MinimumWidth = 48;
        gcs::MessageAction continueAction(L"Continue"); continueAction.DisplayText = GBMP_TR(L"确定全部添加"); continueAction.IsSolid = true; continueAction.MinimumWidth = 48;
        gcs::MessageAction action = pViewService->ShowMessageBox(GBMP_TR(L"警告"), strMessage, gcs::EMessageType::Warning, { cancelAction, skipAction, continueAction });
        if (action == cancelAction) // 用户选择了取消
        {
            return EDuplicateChoice::Cancel;
        }
        else if (action == skipAction) // 用户选择了跳过
        {
            return EDuplicateChoice::Skip;
        }
        else if (action == continueAction) // 用户选择了继续
        {
            return EDuplicateChoice::Continue;
        }
        else // 用户未做选择，而是关闭了弹窗（点击×，或按ESC）
        {
            return EDuplicateChoice::Cancel;
        }
    }

    /// \brief 用以创建族实例的数据
    struct FamilyInstanceCreationData
    {
        bool IsStandaloneEdition = false;       ///< 是否是单机版
        std::wstring FamilyNameInDocument;      ///< 文档中用于创建实例的族名称。对于协同版，若文档中按此名称找不到，则会从本地库载入
        std::wstring FamilyNameInLocalDb;       ///< 本地库中以备载入的族名称
        std::wstring CategoryCode;              ///< 本地库中以备载入的族分类编码
        std::wstring ExpectedFamilyTypeName;    ///< 期望用以创建实例的族类型名称。若不存在，则默认使用族的第一个族类型
    };

    /// \brief 创建族实例
    ///
    /// \param creationData 用以创建族实例的数据
    /// \return 若成功发出创建实例命令，则返回true；否则，返回false
    bool CreateFamilyInstance(const FamilyInstanceCreationData &creationData)
    {
        gcmp::ICommandManager* pCmdMgr = gcmp::ICommandManager::Get();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pCmdMgr != nullptr, L"pCmdMgr为空", L"GMEP", L"2024-01-30");

        gcmp::CommandParameters cmdParams;
        cmdParams[L"needLoadFamily"] = true;                                        // 此参数实际是用以区分是否是公共库布置场景，当前文件中应始终为true
        cmdParams[L"elementId"] = -1;                                               // 此参数是在创建类似实例的场景下才会使用到，当前文件中只需给定一个无效值
        cmdParams[L"familyName"] = creationData.FamilyNameInLocalDb;                // 若载入族，db3 里的要载入的族名
        cmdParams[L"uniqueFamilyName"] = creationData.FamilyNameInDocument;         // 若载入族，载入后使用的族名， 可以为空（为空时认为与familyName 一样）
        cmdParams[L"instanceTypeName"] = creationData.ExpectedFamilyTypeName;       // 期望用以创建实例的族类型名称。若不存在，则默认使用族的第一个族类型
        cmdParams[L"categoryCode"] = creationData.CategoryCode;                     // 若载入族，db3 里的要载入的族分类编码
        cmdParams[L"bLoadFromPublicLibrary"] = creationData.IsStandaloneEdition;    // 是否是直接使用公共库的族
        pCmdMgr->SendCommand(L"GmepCreateSimilarElementCmd", cmdParams);

        return true;
    }

    /// \brief 将gcs::IComponentDto转换到gmepgcs::PublicComponentDto
    std::shared_ptr<gmepgcs::PublicComponentDto> ConvertToPublicComponentDto(const std::shared_ptr<gcs::IComponentDto> &spIComponentDto)
    {
        if (!spIComponentDto)
        {
            return nullptr;
        }

        std::shared_ptr<gmepgcs::PublicComponentDto> spPublicComponentDto = std::make_shared<gmepgcs::PublicComponentDto>();
        if (!spPublicComponentDto)
        {
            return nullptr;
        }

        // id
        spPublicComponentDto->Id = spIComponentDto->Id();

        // name
        spPublicComponentDto->Name = spIComponentDto->Name();

        return spPublicComponentDto;
    };
}

namespace gmepgcs
{
    // 载入一个公共库构件，若本文档已经存在此同名的构件， 提示用户， 取消，跳过，还是存为副本 （1）， 取消或跳过则不载入，返回false
    bool GmepLocalComponentOpertions::Load(gcs::EGcsEdition edition, const std::wstring &id, const std::wstring &name, const std::wstring &version, const std::shared_ptr<gcs::IGcsViewOptions> &spViewOptions)
    {
        if (edition == gcs::EGcsEdition::Standalone)
        {
            std::wstring strUniqueName, strCategoryCode;
            bool bSkipped = false;
            return LoadOnePublicComponent(id, name, version, spViewOptions.get(), strUniqueName, strCategoryCode, bSkipped);
        }
        else // 协同版添加到项目构件库 并下载
        {
            std::map<std::wstring, ComponentInfos> retCompMap;
            bool bSkipped = false;
            bool succ = LoadOneProjectComponent(id, name, version, spViewOptions.get(), retCompMap, bSkipped);
            if (succ)
            {
                UIService * pUiservice = UIService::Get();
                if (pUiservice)
                    pUiservice->RefreshProjectPage();
            }
            return succ;
        }
    }

    std::map<std::wstring, bool> GmepLocalComponentOpertions::LoadInBatch(gcs::EGcsEdition edition, const std::map<std::wstring, std::wstring> &idNames, const std::wstring &version, const std::shared_ptr<gcs::IGcsViewOptions> &spViewOptions)
    {
        if (edition == gcs::EGcsEdition::Standalone)
        {
            return LoadInBatchPublicComponents(idNames, version, spViewOptions);
        }
        else // 协同版添加到项目构件库 并下载
        {
            std::map<std::wstring, bool> retMap = LoadInBatchProjectComponents(idNames, version, spViewOptions.get());
            if (retMap.size() > 0)
            {
                UIService * pUiservice = UIService::Get();
                if (pUiservice)
                    pUiservice->RefreshProjectPage();
            }
            return retMap;
        }
    }

    bool GmepLocalComponentOpertions::Place(gcs::EGcsEdition edition, const std::shared_ptr<gcs::IComponentDto> &spComponent, const std::shared_ptr<gcs::IComponentPlacingOptions> &spPlacingOptions, const std::shared_ptr<gcs::IGcsViewOptions> &spViewOptions)
    {
        DBG_WARN_AND_RETURN_FALSE_UNLESS(spComponent != nullptr && spPlacingOptions != nullptr, L"pCloudService为空", L"GMEP", L"2024-01-30");
        std::wstring id = spComponent->Id();
        std::wstring name = spComponent->Name();
        std::wstring version = spComponent->SoftwareVersion();
        std::wstring familyTypeName = spPlacingOptions->FamilyTypeNameToBePlaced();

        const std::vector<std::shared_ptr<gcs::IComponentParameterDto>>& instanceParams = spPlacingOptions->InstanceParameters();

        switch (edition)
        {
        case gcs::EGcsEdition::Collaboration:
            return Place4CollaborationEdition(id, name, version, familyTypeName, instanceParams, spViewOptions);
        case gcs::EGcsEdition::Standalone:
            return Place4StandaloneEdition(id, name, version, familyTypeName, instanceParams, spViewOptions);
        default:
            DBG_WARN(L"unsupported edition", L"GMEP", L"2024-01-30");
            return false;
        }
    }

    //协同版公有云 添加公共库构件到项目，并下载
    std::map<std::wstring, bool> GmepLocalComponentOpertions::AddPublicComponentsToPorjectAndDownload(const std::wstring& projectId, const std::wstring& enterpriseId,
        const std::vector<std::wstring>& publicIdVec, gcs::IGcsViewOptions *pViewOptions, std::map<std::wstring, ComponentInfos>& retCompMap)
    {
        std::map<std::wstring, bool> retLoadResultMap;
        gmepgcs::ProjectCloudComponentService* pCloudService = gmepgcs::ProjectCloudComponentService::Get();
        DBG_WARN_AND_RETURN_UNLESS(pCloudService != nullptr && !projectId.empty(), retLoadResultMap, L"pCloudService为空", L"GMEP", L"2024-01-30");
        ProjectLocalComponentService * pProjectLocalComponentService = ProjectLocalComponentService::Get();
        DBG_WARN_AND_RETURN_UNLESS(pProjectLocalComponentService, retLoadResultMap, L"pProjectLocalComponentService为空", L"GMEP", L"2024-01-30");

        // 添加到此协同项目
        if (pViewOptions != nullptr)
            pViewOptions->ReportProgress(GBMP_TR(L"正在载入"), 0.0f);
        // 20230930若是私有化部署环境，则当成本地gac添加， 若是公有云则调用协同接口直接添加

        retCompMap = pCloudService->AddComponentFromPublic(projectId, publicIdVec);
        DBG_WARN_AND_RETURN_UNLESS(retCompMap.size() > 0, retLoadResultMap, L"retCompMap为空", L"GMEP", L"2024-01-30");
        if (pViewOptions != nullptr)
            pViewOptions->ReportProgress(GBMP_TR(L"正在载入"), 0.1f);


        for (auto& strId : publicIdVec)
        {
            bool findthecomp = false;
            for (auto& compItem : retCompMap)
            {
                if (compItem.second.wstrPublicCompId == strId)
                {
                    findthecomp = true;
                    break;
                }
            }
            if (findthecomp)
                retLoadResultMap.emplace(strId, true);
            else
                retLoadResultMap.emplace(strId, false);
        }

        // 获取新增的项目级构件并下载至本地缓存       
        std::map<std::wstring, ComponentInfos> compMap = retCompMap;
        bool downloadSucc = pProjectLocalComponentService->SaveAddedComponentFromPublicToProjectDb(projectId, enterpriseId, compMap);
        DBG_WARN_AND_RETURN_UNLESS(downloadSucc, retLoadResultMap, L"downloadSucc为false", L"GMEP", L"2024-01-30");
        if (pViewOptions != nullptr)
            pViewOptions->ReportProgress(GBMP_TR(L"正在载入"), 1.0f);

        return retLoadResultMap;
    }

    //协同版私有化部署 添加公共库构件到项目
    std::map<std::wstring, bool> GmepLocalComponentOpertions::AddPublicComponentsToPorjectAndDownloadForPrivate(const std::wstring& projectId, const std::wstring& enterpriseId,
        const std::map<std::wstring, std::wstring> &idNameMap, const std::wstring &version, gcs::IGcsViewOptions *pViewOptions, std::map<std::wstring, ComponentInfos>& retCompMap)
    {
        std::map<std::wstring, bool> retLoadResultMap;
        gmepgcs::ProjectCloudComponentService* pCloudService = gmepgcs::ProjectCloudComponentService::Get();
        DBG_WARN_AND_RETURN_UNLESS(pCloudService != nullptr && !projectId.empty(), retLoadResultMap, L"pCloudService为空", L"GMEP", L"2024-01-30");
        ProjectLocalComponentService * pProjectLocalComponentService = ProjectLocalComponentService::Get();
        DBG_WARN_AND_RETURN_UNLESS(pProjectLocalComponentService, retLoadResultMap, L"pProjectLocalComponentService为空", L"GMEP", L"2024-01-30");

        // 20230930若是私有化部署环境，上传公共构件到协同项目, 并下载到本地项目缓存
        retCompMap = pProjectLocalComponentService->AddComponentFromPublicForPrivate(projectId, idNameMap, version, pViewOptions);

        for (auto& strId : idNameMap)
        {
            bool findthecomp = false;
            for (auto& compItem : retCompMap)
            {
                //std::wstring str = strId->first;
                if (compItem.second.wstrPublicCompId == strId.first)
                {
                    findthecomp = true;
                    break;
                }
            }
            if (findthecomp)
                retLoadResultMap.emplace(strId.first, true);
            else
                retLoadResultMap.emplace(strId.first, false);
        }

        DBG_WARN_AND_RETURN_UNLESS(retCompMap.size() > 0, retLoadResultMap, L"retCompMap为空", L"GMEP", L"2024-01-30");
        if (pViewOptions != nullptr)
            pViewOptions->ReportProgress(GBMP_TR(L"正在载入"), 1.0f);

        return retLoadResultMap;
    }


    //协同版
    bool GmepLocalComponentOpertions::LoadOneProjectComponent(const std::wstring& id, const std::wstring &name, const std::wstring &version, gcs::IGcsViewOptions *pViewOptions, std::map<std::wstring, ComponentInfos>& retCompMap, bool &bSkipped)
    {
        bSkipped = false;
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pViewOptions, L"pViewOptions为空", L"GMEP", L"2024-01-30");
        pViewOptions->ReportProgress(GBMP_TR(L"正在载入"));

        // 1. 检查是否已添加到协同项目
        std::shared_ptr<PublicComponentAddedCheck> spPublicComponentAddedCheck = std::make_shared<PublicComponentAddedCheck>();
        DBG_WARN_AND_RETURN_UNLESS(spPublicComponentAddedCheck, false, L"spPublicComponentAddedCheck为空", L"GMEP", L"2024-01-30");

        IProjectManager* pManager = IProjectManager::Get();
        DBG_WARN_AND_RETURN_UNLESS(pManager != nullptr, false, L"pManager为空", L"GMEP", L"2024-01-30");
        std::wstring projectId = pManager->GetCurrentProjectId();
        DBG_WARN_AND_RETURN_UNLESS(!projectId.empty(), false, L"projectId为空", L"GMEP", L"2024-01-30");
        spPublicComponentAddedCheck->ProjectId = projectId;

        std::shared_ptr<PublicComponentDto> spPublicComponentDto = std::make_shared<PublicComponentDto>();
        DBG_WARN_AND_RETURN_UNLESS(spPublicComponentDto, false, L"spPublicComponentDto为空", L"GMEP", L"2024-01-30");
        spPublicComponentDto->Id = id;
        spPublicComponentDto->Name = name;
        spPublicComponentAddedCheck->PublicComponents.push_back(spPublicComponentDto);

        gmepgcs::ProjectCloudComponentService* pCloudService = gmepgcs::ProjectCloudComponentService::Get();
        DBG_WARN_AND_RETURN_UNLESS(pCloudService != nullptr, false, L"pCloudService为空", L"GMEP", L"2024-01-30");
        std::vector<std::shared_ptr<PublicComponentAddedCheckResult>> publicComponentAddedCheckResults = pCloudService->CheckPublicComponentAdded(spPublicComponentAddedCheck);
        DBG_WARN_AND_RETURN_UNLESS(!publicComponentAddedCheckResults.empty(), false, L"publicComponentAddedCheckResults为空", L"GMEP", L"2024-01-30");

        std::shared_ptr<PublicComponentAddedCheckResult> spPublicComponentAddedCheckResult = publicComponentAddedCheckResults.front();
        DBG_WARN_AND_RETURN_UNLESS(spPublicComponentAddedCheckResult, false, L"spPublicComponentAddedCheckResult为空", L"GMEP", L"2024-01-30");
        if (spPublicComponentAddedCheckResult->Exist)
        {
            EDuplicateChoice userChoice = PopUpDuplicateWarning(pViewOptions, true); // messageBox, 取消，跳过，还是存为副本 （1）
            if (userChoice != EDuplicateChoice::Continue)
            {
                if (userChoice == EDuplicateChoice::Skip) // 搜集已存在的项目构件数据，用以继续布置操作
                {
                    bSkipped = true;
                    ComponentInfos componentInfos;
                    {
                        componentInfos.wstrPublicCompId = spPublicComponentAddedCheckResult->PublicComponentId;
                        componentInfos.wstrName = spPublicComponentAddedCheckResult->Name;
                        componentInfos.wstrCategoryCode = spPublicComponentAddedCheckResult->CategoryCode;
                    }
                    retCompMap.emplace(spPublicComponentAddedCheckResult->SuiteId, componentInfos);
                }
                return false;
            }
        }

        // 2. 添加到协同项目并下载
        std::wstring enterpriseId = pManager->GetCurrentEnterpriseId();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(!enterpriseId.empty(), L"enterpriseId为空", L"GMEP", L"2024-01-30");

        std::map<std::wstring, bool> retResultMap;
        if (gmep::GmepVersionUtils::IsPrivatizationEnvironment())
        {
            std::map<std::wstring, std::wstring> idNameMap;
            idNameMap.emplace(id, name);
            retResultMap = AddPublicComponentsToPorjectAndDownloadForPrivate(projectId, enterpriseId, idNameMap, version, pViewOptions, retCompMap);
        }
        else
        {
            std::vector<std::wstring> publicIdVec;
            publicIdVec.push_back(id);
            retResultMap = AddPublicComponentsToPorjectAndDownload(projectId, enterpriseId, publicIdVec, pViewOptions, retCompMap);
        }

        // 3. 汇报载入结果
        DBG_WARN_AND_RETURN_FALSE_UNLESS(!retResultMap.empty(), L"retResultMap为空", L"GMEP", L"2024-01-30");
        bool bSuccess = retResultMap.begin()->second;
        if (bSuccess)
        {
            pViewOptions->ReportSuccess(GBMP_TR(L"载入成功"));
        }
        else
        {
            pViewOptions->ReportFailure(GBMP_TR(L"载入失败"));
        }

        return bSuccess;
    }

    //协同版
    std::map<std::wstring, bool> GmepLocalComponentOpertions::LoadInBatchProjectComponents(const std::map<std::wstring, std::wstring> &idNames, const std::wstring &version, gcs::IGcsViewOptions *pViewOptions)
    {
        std::map<std::wstring, bool> retResultMap;
        DBG_WARN_AND_RETURN_UNLESS(pViewOptions, retResultMap, L"pViewOptions为空", L"GMEP", L"2024-01-30");
        pViewOptions->ReportProgress(GBMP_TR(L"正在载入"), 0.0f);

        // 1. 检查是否已添加到协同项目
        std::shared_ptr<PublicComponentAddedCheck> spPublicComponentAddedCheck = std::make_shared<PublicComponentAddedCheck>();
        DBG_WARN_AND_RETURN_UNLESS(spPublicComponentAddedCheck, retResultMap, L"spPublicComponentAddedCheck为空", L"GMEP", L"2024-01-30");

        gmepgcs::IProjectManager* pManager = IProjectManager::Get();
        DBG_WARN_AND_RETURN_UNLESS(pManager != nullptr, retResultMap, L"pManager为空", L"GMEP", L"2024-01-30");
        std::wstring projectId = pManager->GetCurrentProjectId();
        DBG_WARN_AND_RETURN_UNLESS(!projectId.empty(), retResultMap, L"pCloudService为空", L"GMEP", L"2024-01-30");
        spPublicComponentAddedCheck->ProjectId = projectId;

        std::vector<std::wstring> publicIdVec;
        for (auto& idNamePair : idNames)
        {
            publicIdVec.emplace_back(idNamePair.first);

            if (std::shared_ptr<PublicComponentDto> spPublicComponentDto = std::make_shared<PublicComponentDto>())
            {
                spPublicComponentDto->Id = idNamePair.first;
                spPublicComponentDto->Name = idNamePair.second;
                spPublicComponentAddedCheck->PublicComponents.push_back(spPublicComponentDto);
            }
        }

        gmepgcs::ProjectCloudComponentService* pCloudService = gmepgcs::ProjectCloudComponentService::Get();
        DBG_WARN_AND_RETURN_UNLESS(pCloudService != nullptr, retResultMap, L"pCloudService为空", L"GMEP", L"2024-01-30");
        std::vector<std::shared_ptr<PublicComponentAddedCheckResult>> publicComponentAddedCheckResults = pCloudService->CheckPublicComponentAdded(spPublicComponentAddedCheck);
        DBG_WARN_AND_RETURN_UNLESS(!publicComponentAddedCheckResults.empty(), retResultMap, L"publicComponentAddedCheckResults为空", L"GMEP", L"2024-01-30");

        std::vector<std::wstring> addedIdVec;
        std::vector<std::wstring> notAddedIdVec;
        std::map<std::wstring, std::wstring> notAddedIdNames;
        for (auto& spPublicComponentAddedCheckResult : publicComponentAddedCheckResults)
        {
            if (!spPublicComponentAddedCheckResult)
            {
                continue;
            }

            if (spPublicComponentAddedCheckResult->Exist)
            {
                addedIdVec.emplace_back(spPublicComponentAddedCheckResult->PublicComponentId);
            }
            else
            {
                std::wstring id = spPublicComponentAddedCheckResult->PublicComponentId;
                notAddedIdVec.emplace_back(id);
                const std::map<std::wstring, std::wstring>::const_iterator iter = idNames.find(id);
                if (iter != idNames.end())
                {
                    notAddedIdNames.emplace(id, iter->second);
                }
            }
        }

        bool bSkipLoaded = false;
        if (!addedIdVec.empty())
        {
            EDuplicateChoice userChoice = PopUpDuplicateWarning(pViewOptions, false);// messageBox, 取消，跳过，还是存为副本 （1）
            if (userChoice == EDuplicateChoice::Cancel) // 若取消, 则取消整个批量载入过程
            {
                return retResultMap;
            }

            if (userChoice == EDuplicateChoice::Skip) // 若跳过, 则跳过所有已添加的公共构件
            {
                bSkipLoaded = true;
            }
        }
        const std::vector<std::wstring> &toAddIds = bSkipLoaded ? notAddedIdVec : publicIdVec;
        const std::map<std::wstring, std::wstring> &toAddIdNames = bSkipLoaded ? notAddedIdNames : idNames;
        if (toAddIds.empty()) // 全部被跳过了
        {
            return retResultMap;
        }

        // 2. 添加到协同项目并下载
        std::wstring enterpriseId = pManager->GetCurrentEnterpriseId();
        DBG_WARN_AND_RETURN_UNLESS(!enterpriseId.empty(), retResultMap, L"projectId为空", L"GMEP", L"2024-01-30");

        std::map<std::wstring, ComponentInfos> retCompMap;
        if (gmep::GmepVersionUtils::IsPrivatizationEnvironment())
        {
            retResultMap = AddPublicComponentsToPorjectAndDownloadForPrivate(projectId, enterpriseId, toAddIdNames, version, pViewOptions, retCompMap);
        }
        else
        {
            retResultMap = AddPublicComponentsToPorjectAndDownload(projectId, enterpriseId, toAddIds, pViewOptions, retCompMap);
        }

        // 3. 汇报载入结果
        size_t totalCount = toAddIds.size();
        size_t successCount = 0;
        size_t failureCount = 0;
        for (auto &resultItem : retResultMap)
        {
            if (resultItem.second)
            {
                successCount++;
            }
            else
            {
                failureCount++;
            }
        }

        if (successCount == totalCount)
        {
            pViewOptions->ReportSuccess(GBMP_TR(L"载入成功"));
            return retResultMap;
        }

        gcs::MessageAction okAction(L"Ok"); okAction.DisplayText = GBMP_TR(L"确定"); okAction.IsSolid = true;
        std::wstring message = failureCount == totalCount ? GBMP_TR(L"全部载入失败") : GBMP_TR(L"部分构件载入失败");
        pViewOptions->ShowMessageBox(L"", message, gcs::EMessageType::Warning, { okAction });
        return retResultMap;
    }

    const gcmp::IParameterDefinition* GetParameterDefByGuid(const gcmp::IDocument* pDoc, const gcmp::UniIdentity& uid)
    {
        const gcmp::IParameterDefinitionLibrary* pLibrary = gcmp::IParameterDefinitionLibrary::Get(pDoc);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pLibrary, L"pLibrary为空", L"GMEP", L"2024-01-30");
        return pLibrary->GetParameterDefinitionByUid(gcmp::UniIdentity(uid));
    }

    bool GetInstanceParameterFromComponent(gcmp::IDocument* pDoc, const std::wstring& categoryCode, 
        const std::vector<std::shared_ptr<gcs::IComponentParameterDto>>& instanceParams,
        std::map<std::wstring, gcmp::OwnerPtr<gcmp::IParameterValueStorage>>& resInstancePropertyValueMap)
    {
        resInstancePropertyValueMap.clear();
        if (categoryCode.empty() || instanceParams.empty())
            return false;

        gmep::IUnitConverterManager* pUnitManager = gmep::IUnitConverterManager::Get(pDoc);
        DBG_WARN_AND_RETURN_UNLESS(pUnitManager, false, L"pUnitManager为空", L"GMEP", L"2024-01-30");
        std::map<std::wstring, short> retUnitInfoMap;
        gmep::IGmepCategoryInfoUtils *pGmepCategoryInfoUtils = gmep::GmepCategoryInfoUtilsHandler::Get().GetUtils();
        DBG_WARN_AND_RETURN_UNLESS(pGmepCategoryInfoUtils, false, L"pGmepCategoryInfoUtils为空", L"GMEP", L"2024-01-30");
        pGmepCategoryInfoUtils->GetGmepUnitInformation(retUnitInfoMap);

        gcmp::OwnerPtr<gmep::IGmepCategoryInfo> pCategory = nullptr;
        

        for (auto& item : instanceParams)
        {
            gcs::IComponentParameterDto* pParam = item.get();
            DBG_WARN_AND_CONTINUE_UNLESS(pParam != nullptr, L"pParam为空", L"GMEP", L"2024-01-30");

            std::wstring strGuid = pParam->Guid();
            DBG_WARN_AND_CONTINUE_UNLESS(!strGuid.empty(), L"paramDef为空", L"GMEP", L"2024-01-30");
            Guid guid = gcmp::GuidUtils::FromString(L"{" + QString::fromStdWString(strGuid).toUpper().toStdWString() + L"}");
            const gcmp::IParameterDefinition* paramDef = GetParameterDefByGuid(pDoc, gcmp::UniIdentity(guid));
            DBG_WARN_AND_CONTINUE_UNLESS(paramDef != nullptr, L"paramDef为空", L"GMEP", L"2024-01-30");

            std::wstring strCode = pParam->Code();
            std::wstring strName = pParam->Name();
            std::wstring strValue = pParam->Value();
            std::wstring strUnitCode = pParam->UnitCode();

            std::wstring strValueInBaseUnit = strValue;
            gcmp::ParameterStorageType iStorageType = paramDef->GetStorageType();
            switch (iStorageType)
            {
            case gcmp::ParameterStorageType::Invalid:
                break;
            case gcmp::ParameterStorageType::None:
                break;
            case gcmp::ParameterStorageType::Custom:
                break;
            case gcmp::ParameterStorageType::Bool:
            {
                //true/false
                std::wstring strBoolValue = QString::fromStdWString(strValue).toUpper().toStdWString();
                int iBoolValue = strBoolValue == L"TRUE" ? 1 : 0;
                gcmp::OwnerPtr<gcmp::IParameterValueStorage> paramStorage = gmep::BaseCommonUtils::GetParameterValueStorageByType((short)iStorageType, L"", 0.0, iBoolValue);
                DBG_WARN_AND_CONTINUE_UNLESS(paramStorage, L"paramStorage为空", L"GMEP", L"2024-01-30");
                resInstancePropertyValueMap.emplace(std::make_pair(strGuid, TransferOwnership(paramStorage)));
            }
                break;
            case gcmp::ParameterStorageType::Int:
            {
                int iValue = 0;
                // 若是枚举，需要将标准码转为int值
                if (paramDef->GetParameterTypeId() == PARAMETER_TYPE(ValueList))
                {
                    if (pCategory == nullptr) // 仅需要枚举时获取一次
                    {
                        bool bGetCategorySucc = pGmepCategoryInfoUtils->GetCategoryInfoByStandardCode(categoryCode, pCategory);
                        DBG_WARN_AND_CONTINUE_UNLESS(bGetCategorySucc && pCategory != nullptr, L"pCategory为空", L"GMEP", L"2024-01-30");
                    }
                    if (pCategory != nullptr)
                    {
                        const gmep::IGmepPropertyInfo * pProp = pCategory->GetPropertyInforByStandardCode(strCode);
                        DBG_WARN_AND_CONTINUE_UNLESS(pProp != nullptr, L"pProp为空", L"GMEP", L"2024-01-30");
                        std::map<std::wstring, int> mapEnumMap = pProp->GetEnumValueStandardCodeList();
                        if (mapEnumMap.find(strValue) != mapEnumMap.end())
                            iValue = mapEnumMap[strValue];
                    }

                }
                else
                {
                    bool success = false;
                    iValue = gcmp::StringUtil::ToNumber<int>(strValue, &success);
                    DBG_WARN_AND_CONTINUE_UNLESS(success, L"转为int失败", L"GMEP", L"2024-01-30");
                }
                gcmp::OwnerPtr<gcmp::IParameterValueStorage> paramStorage = gmep::BaseCommonUtils::GetParameterValueStorageByType((short)iStorageType, L"", 0.0, iValue);
                DBG_WARN_AND_CONTINUE_UNLESS(paramStorage, L"paramStorage为空", L"GMEP", L"2024-01-30");
                resInstancePropertyValueMap.emplace(std::make_pair(strGuid, TransferOwnership(paramStorage)));

            }
                break;
            case gcmp::ParameterStorageType::Double:
            {
                // double 可能需要进行单位转换
                bool success = false;
                double value = gcmp::StringUtil::ToNumber<double>(strValue, &success);
                gcmp::UniIdentity uid = gmep::GmepUnitUtils::GetGmepUnitType(paramDef);
                if (success)
                {
                    double dValueInBase;
                    const gmep::IUnitConverter* pUnitConverter = pUnitManager->GetUnitConverter(uid);
                    if (pUnitConverter) // 有单位设置的double型 按照精度显示
                    {
                        dValueInBase = gmep::GmepUnitUtils::ConvertToStandardUnitValue(pDoc, uid, value, retUnitInfoMap[strUnitCode]);
                    }
                    else // 无单位设置的double型 按照3位精度显示
                    {
                        dValueInBase = value;
                    }
                    gcmp::OwnerPtr<gcmp::IParameterValueStorage> paramStorage = gmep::BaseCommonUtils::GetParameterValueStorageByType((short)iStorageType, L"", dValueInBase, 0);
                    DBG_WARN_AND_CONTINUE_UNLESS(paramStorage, L"paramStorage为空", L"GMEP", L"2024-01-30");
                    resInstancePropertyValueMap.emplace(std::make_pair(strGuid, TransferOwnership(paramStorage)));
                }
            }
                break;
            case gcmp::ParameterStorageType::String:
            {
                gcmp::OwnerPtr<gcmp::IParameterValueStorage> paramStorage = gmep::BaseCommonUtils::GetParameterValueStorageByType((short)iStorageType, strValue, 0.0, 0);
                DBG_WARN_AND_CONTINUE_UNLESS(paramStorage, L"paramStorage为空", L"GMEP", L"2024-01-30");
                resInstancePropertyValueMap.emplace(std::make_pair(strGuid, TransferOwnership(paramStorage)));
            }
                break;
            case gcmp::ParameterStorageType::Coordinates:
                break;
            case gcmp::ParameterStorageType::ElementId:
                break;
            case gcmp::ParameterStorageType::BuildingStorey:
                break;
            case gcmp::ParameterStorageType::Color:
                break;
            case gcmp::ParameterStorageType::StandardCodeReference:
                break;
            case gcmp::ParameterStorageType::Geometry:
                break;
            case gcmp::ParameterStorageType::Guid:
                break;
            case gcmp::ParameterStorageType::Count:
                break;
            default:
                break;
            }
            

        }

        return true;
    }

    bool GmepLocalComponentOpertions::Place4StandaloneEdition(const std::wstring & id, const std::wstring & name, const std::wstring & version, const std::wstring & familyTypeName,
        const std::vector<std::shared_ptr<gcs::IComponentParameterDto>>& instanceParams, 
        const std::shared_ptr<gcs::IGcsViewOptions>& spViewOptions)
    {
        DBG_WARN_AND_RETURN_FALSE_UNLESS(spViewOptions, L"spViewOptions为空", L"GMEP", L"2024-01-30");

        gcmp::IDocument* pDoc = AppService::GetCurrentDocument();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空", L"GMEP", L"2024-01-30");

        gmepgcs::ProjectLoadedComponentService* pLoadedService = gmepgcs::ProjectLoadedComponentService::Get();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pLoadedService, L"pLoadedService为空", L"GMEP", L"2024-01-30");

        // 1. 下载公共构件到本地并载入到文档
        std::wstring strUniqueName, strCategoryCode;
        bool bSkipped = false;
        bool bDownloadedAndLoaded = LoadOnePublicComponent(id, name, version, spViewOptions.get(), strUniqueName, strCategoryCode, bSkipped);// 先走载入流程， 若失败，或用户选择 取消、跳过，则返回false
        
        // 2. 若未执行下载及载入，且并非跳过，则不进行布置
        if (!bDownloadedAndLoaded && !bSkipped)
        {
            return false;
        }

        // 3. 准备创建实例所需的数据
        FamilyInstanceCreationData familyInstanceCreationData;
        familyInstanceCreationData.IsStandaloneEdition = true;
        familyInstanceCreationData.ExpectedFamilyTypeName = familyTypeName;

        // 4. 若执行了下载及载入，则使用已载入的构件进行布置
        if (bDownloadedAndLoaded)
        {
            DBG_WARN_AND_RETURN_FALSE_UNLESS(!strUniqueName.empty(), L"strUniqueName为空", L"GMEP", L"2024-01-30");
            DBG_WARN_AND_RETURN_FALSE_UNLESS(!strCategoryCode.empty(), L"strCategoryCode为空", L"GMEP", L"2024-01-30");
            familyInstanceCreationData.FamilyNameInLocalDb = name;
            familyInstanceCreationData.FamilyNameInDocument = strUniqueName;
            familyInstanceCreationData.CategoryCode = strCategoryCode;
        }
        // 5. 若未执行下载及载入，但用户选择了跳过，则询问用户是否要布置已载入的构件
        else if (bSkipped)
        {
            gcs::MessageAction noAction(L"No"); noAction.DisplayText = GBMP_TR(L"否"); noAction.IsSolid = false; noAction.MinimumWidth = 48;
            gcs::MessageAction yesAction(L"YES"); yesAction.DisplayText = GBMP_TR(L"是"); yesAction.IsSolid = true; yesAction.MinimumWidth = 48;
            gcs::MessageAction resultAction = spViewOptions->ShowMessageBox(GBMP_TR(L"提示"), GBMP_TR(L"是否布置已载入的构件？"), gcs::EMessageType::Info, { noAction, yesAction });
            // 5.1 若用户未选择是，则不进行布置
            if (resultAction != yesAction)
            {
                return false;
            }

            // 5.2 若用户选择是，则使用已载入的构件进行布置
            familyInstanceCreationData.FamilyNameInLocalDb = name; // 不能为空，更底层的command会校验此字段非空，并以此去文档中查找构件
            familyInstanceCreationData.FamilyNameInDocument = name;
            familyInstanceCreationData.CategoryCode = L"";
        }

        // 20231130若有产品库实例参数， 存入GjwInfo.m_mapInstanceProperty
        std::map<std::wstring, gcmp::OwnerPtr<gcmp::IParameterValueStorage>> retInstancePropertyValueMap;
        gmep::GjwPlaceInstanceInfo& GjwInfo = gmep::GjwPlaceInstanceInfo::Get();
        GjwInfo.m_mapInstanceProperty.clear();
        if (GetInstanceParameterFromComponent(pDoc, familyInstanceCreationData.CategoryCode, instanceParams, retInstancePropertyValueMap) && !retInstancePropertyValueMap.empty())
        {
            GjwInfo.m_mapInstanceProperty = std::move(retInstancePropertyValueMap);
           
        }

        // 6. 关闭公共库窗口
        spViewOptions->HideMainWindow();

        // 7. 触发创建实例的命令
        bool bCreateInstance = CreateFamilyInstance(familyInstanceCreationData);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(bCreateInstance, L"bCreateInstance is false", L"GMEP", L"2024-01-30");

        //spViewOptions->ShowMainWindow(edition, L"/component/all");
        return true;
    }

    bool GmepLocalComponentOpertions::Place4CollaborationEdition(const std::wstring & id, const std::wstring & name, const std::wstring & version, const std::wstring & familyTypeName,
        const std::vector<std::shared_ptr<gcs::IComponentParameterDto>>& instanceParams,
        const std::shared_ptr<gcs::IGcsViewOptions>& spViewOptions)
    {
        DBG_WARN_AND_RETURN_FALSE_UNLESS(spViewOptions, L"spViewOptions为空", L"GMEP", L"2024-01-30");

        gcmp::IDocument* pDoc = AppService::GetCurrentDocument();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空", L"GMEP", L"2024-01-30");

        gmepgcs::ProjectLoadedComponentService* pLoadedService = gmepgcs::ProjectLoadedComponentService::Get();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pLoadedService != nullptr, L"pLoadedService为空", L"GMEP", L"2024-01-30");

        // 1. 添加到协同项目并下载到本地
        std::map<std::wstring, ComponentInfos> retCompMap;
        bool bSkipped = false;
        bool bAddedAndDownloaded = LoadOneProjectComponent(id, name, version, spViewOptions.get(), retCompMap, bSkipped); // 先添加到项目构件库 并下载， 若失败，或用户选择 取消、跳过，则返回false
                                                                                                                          
        // 2. 若未执行添加及下载，且并非跳过，则不进行布置
        if (!bAddedAndDownloaded && !bSkipped)
        {
            return false;
        }

        // 3. 准备创建实例所需的数据
        DBG_WARN_AND_RETURN_FALSE_UNLESS(!retCompMap.empty(), L"retCompMap为空", L"GMEP", L"2024-01-30");
        std::pair<std::wstring, ComponentInfos> projectComponentPair = *(retCompMap.begin());

        FamilyInstanceCreationData familyInstanceCreationData;
        familyInstanceCreationData.IsStandaloneEdition = false;
        familyInstanceCreationData.CategoryCode = projectComponentPair.second.wstrCategoryCode;
        familyInstanceCreationData.ExpectedFamilyTypeName = familyTypeName;

        // 4. 若执行了添加及下载，则使用已下载的构件进行布置
        if (bAddedAndDownloaded)
        {
            familyInstanceCreationData.FamilyNameInLocalDb = projectComponentPair.second.wstrName;
            familyInstanceCreationData.FamilyNameInDocument = pLoadedService->GetUniqueFamilyName(pDoc, projectComponentPair.second.wstrName);
        }
        // 5. 若未执行添加及下载，但用户选择了跳过，则询问用户是否要布置已添加的构件
        else if (bSkipped)
        {
            gcs::MessageAction noAction(L"No"); noAction.DisplayText = GBMP_TR(L"否"); noAction.IsSolid = false; noAction.MinimumWidth = 48;
            gcs::MessageAction yesAction(L"YES"); yesAction.DisplayText = GBMP_TR(L"是"); yesAction.IsSolid = true; yesAction.MinimumWidth = 48;
            gcs::MessageAction resultAction = spViewOptions->ShowMessageBox(GBMP_TR(L"提示"), GBMP_TR(L"是否布置已添加的构件？"), gcs::EMessageType::Info, { noAction, yesAction });
            // 5.1 若用户未选择是，则不进行布置
            if (resultAction != yesAction)
            {
                return false;
            }

            /***
            /* 此时布置，会遇到几类情形：
            /* 1、情形1：
            /* 公共构件已添加到协同项目，但添加后生成的项目构件尚未下载到本地数据库。
            /* 处理逻辑：下载项目构件到本地库 -> 载入工作单元文档 -> 并触发布置。
            /* 
            /* 2、情形2：
            /* 公共构件已添加到协同项目，且添加后生成的项目构件已下载到本地数据库，但尚未载入到工作单元文档。
            /* 处理逻辑：将本地库中的项目构件载入工作单元文档 -> 并触发布置。（无需考虑云端库与本地库之间的构件数据同步）。
            /* 
            /* 3、情形3：
            /* 公共构件已添加到协同项目，且添加后生成的项目构件已下载到本地数据库，且已载入到工作单元文档。
            /* 处理逻辑：直接使用文档中已载入的构件进行布置。（无需考虑云端库、与本地库、与工作单元之间的构件数据同步）。
            ***/

            // 5.2 检查已添加的项目构件是否已下载到本地，若未下载，则下载
            IProjectManager *pProjectManager = IProjectManager::Get();
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pProjectManager, L"pProjectManager为空", L"GMEP", L"2024-01-30");
            const std::wstring projectId = pProjectManager->GetCurrentProjectId();
            DBG_WARN_AND_RETURN_FALSE_UNLESS(!projectId.empty(), L"projectId为空", L"GMEP", L"2024-01-30");

            std::wstring downloadedFamilyName;
            std::vector<std::wstring> downloadedFamilyTypeNames;
            bool bEnsurePrjCompDownloaded = EnsureProjectComponentDownloaded(projectId, projectComponentPair, downloadedFamilyName);
            if (!bEnsurePrjCompDownloaded)
            {
                spViewOptions->ReportFailure(GBMP_TR(L"从本地库获取构件失败"));
                DBG_WARN(L"bEnsurePrjCompDownloaded is false", L"GMEP", L"2024-01-30");
                return false;
            }

            // 5.3 检查项目构件是否已载入到文档中
            std::wstring loadedFamilyName;
            bool bPrjCompLoaded = CheckProjectComponentLoaded(pDoc, projectComponentPair, loadedFamilyName);

            // 5.4 若已载入，则使用已载入的构件进行布置
            if (bPrjCompLoaded)
            {
                familyInstanceCreationData.FamilyNameInLocalDb = downloadedFamilyName;
                familyInstanceCreationData.FamilyNameInDocument = loadedFamilyName;
            }
            // 5.5 若未载入，则使用已下载的构件进行布置
            else
            {
                familyInstanceCreationData.FamilyNameInLocalDb = downloadedFamilyName;
                familyInstanceCreationData.FamilyNameInDocument = pLoadedService->GetUniqueFamilyName(pDoc, downloadedFamilyName);
            }
        }

        // 20231130若有产品库实例参数， 存入GjwInfo.m_mapInstanceProperty
        std::map<std::wstring, gcmp::OwnerPtr<gcmp::IParameterValueStorage>> retInstancePropertyValueMap;
        gmep::GjwPlaceInstanceInfo& GjwInfo = gmep::GjwPlaceInstanceInfo::Get();
        GjwInfo.m_mapInstanceProperty.clear();
        if (GetInstanceParameterFromComponent(pDoc, familyInstanceCreationData.CategoryCode, instanceParams, retInstancePropertyValueMap) && !retInstancePropertyValueMap.empty())
        {
            GjwInfo.m_mapInstanceProperty = std::move(retInstancePropertyValueMap);
        }


        // 6. 关闭公共库窗口
        spViewOptions->HideMainWindow();

        // 7. 关闭项目库窗口
        UIService * pUiservice = UIService::Get();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pUiservice, L"pUiservice为空", L"GMEP", L"2024-01-30");
        pUiservice->HideMainWindow();

        // 8. 触发创建实例的命令
        bool bCreateInstance = CreateFamilyInstance(familyInstanceCreationData);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(bCreateInstance, L"bCreateInstance is false", L"GMEP", L"2024-01-30");

        //spViewOptions->ShowMainWindow(edition, L"/component/all");
        return true;
    }

    bool GmepLocalComponentOpertions::EnsureProjectComponentDownloaded(const std::wstring & projectId, const std::pair<std::wstring, ComponentInfos>& projectComponent, std::wstring & downloadedfamilyName)
    {
        downloadedfamilyName = L"";

        // 1. 检查是否已下载到本地库
        const std::wstring &projectComponentId = projectComponent.first;
        std::tuple<int, int, std::wstring> downloadedProjectComponent;
        bool bDownloaded = ComponentSqlUtils::CheckComponentExisted(projectId, projectComponentId, downloadedProjectComponent);

        // 2. 若已下载，则直接返回
        if (bDownloaded)
        {
            int dirtyFlag = std::get<1>(downloadedProjectComponent);
            if (static_cast<int>(GmepComponentDirtyFlag::LocalDeleted) == dirtyFlag)
            {
                DBG_WARN(L"dirtyFlag is LocalDeleted", L"GMEP", L"2024-01-30");
                return false;
            }

            downloadedfamilyName = std::get<2>(downloadedProjectComponent);
            return true;
        }
        
        // 3. 若未下载到本地库，则进行下载
        IProjectManager* pProjectManager = IProjectManager::Get();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pProjectManager, L"pProjectManager为空", L"GMEP", L"2024-01-30");

        std::wstring enterpriseId = pProjectManager->GetCurrentEnterpriseId();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(!enterpriseId.empty(), L"enterpriseId为空", L"GMEP", L"2024-01-30");

        ProjectLocalComponentService * pProjectLocalComponentService = ProjectLocalComponentService::Get();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pProjectLocalComponentService, L"pProjectLocalComponentService为空", L"GMEP", L"2024-01-30");

        std::map<std::wstring, ComponentInfos> compMap;
        compMap.emplace(projectComponent);
        bDownloaded = pProjectLocalComponentService->SaveAddedComponentFromPublicToProjectDb(projectId, enterpriseId, compMap);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(bDownloaded, L"bDownloaded为false", L"GMEP", L"2024-01-30");

        downloadedfamilyName = projectComponent.second.wstrName;
        return true;
    }

    bool GmepLocalComponentOpertions::CheckProjectComponentLoaded(gcmp::IDocument * pDoc, const std::pair<std::wstring, ComponentInfos>& projectComponent, std::wstring & loadedFamilyName)
    {
        loadedFamilyName = L"";
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空", L"GMEP", L"2024-01-30");

        ProjectLoadedComponentService *pProjectLoadedComponentService = ProjectLoadedComponentService::Get();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pProjectLoadedComponentService, L"pProjectLoadedComponentService为空", L"GMEP", L"2024-01-30");

        const std::wstring &projectComponentId = projectComponent.first;
        std::shared_ptr<IProjectComponent> spLoadedProjectComponent = pProjectLoadedComponentService->FindLoadedComponentByCloudId(projectComponentId);
        if (spLoadedProjectComponent)
        {
            loadedFamilyName = spLoadedProjectComponent->Name;
            return true;
        }
        
        return false;
    }
    
    //单机版 pViewOptions 可以为空， 为空不需要设置进度条
    std::map<std::wstring, bool> GmepLocalComponentOpertions::SyncAndLoadPublicComponents(gcmp::IDocument* pDoc, const std::vector<std::tuple<std::wstring, std::wstring, std::wstring>>& idNameUniqueNameVec,
        const std::map<std::wstring, std::wstring> &idNameMap, const std::wstring & version, gcs::IGcsViewOptions *pViewOptions,
        std::map<std::wstring, std::wstring>& idCategoryCodeMap)
    {        
        std::map<std::wstring, bool> retLoadResultMap;

        gmepgcs::ProjectLoadedComponentService* loadedCompnentService = gmepgcs::ProjectLoadedComponentService::Get();
        gmepgcs::ProjectLocalComponentService* pCompService = gmepgcs::ProjectLocalComponentService::Get();

        DBG_WARN_AND_RETURN_UNLESS(pCompService != nullptr && loadedCompnentService != nullptr, retLoadResultMap, L"loadedCompnentService为空", L"GMEP", L"2024-01-30");
        DBG_WARN_AND_RETURN_UNLESS(pDoc != nullptr && idNameUniqueNameVec.size() > 0 && !idNameMap.empty(), retLoadResultMap, L"输入参数非法", L"GMEP", L"2024-01-30");
        if(pViewOptions != nullptr)
            pViewOptions->ReportProgress(GBMP_TR(L"正在载入"), 0.0f);
        // 下载公共库数据           
        bool succ = pCompService->SyncPublicComponents(idNameMap, version, idCategoryCodeMap);
        if (pViewOptions != nullptr)
            pViewOptions->ReportProgress(GBMP_TR(L"正在载入"), 0.2f);

        // 载入流程
        int succCount = 0;
        if (succ && idCategoryCodeMap.size()>0 && idNameUniqueNameVec.size() > 0)
        {
            float dInterval = 0.8f / idNameUniqueNameVec.size();
            float currentProgress = 0.2f;
            for (auto& item: idNameUniqueNameVec)
            {
                currentProgress += dInterval;
                if (pViewOptions != nullptr)
                    pViewOptions->ReportProgress(GBMP_TR(L"正在载入"), currentProgress);

                std::wstring id, name, uniqueName, categoryCode;
                std::tie(id, name, uniqueName) = item;
                if (idCategoryCodeMap.find(id) != idCategoryCodeMap.end())
                {
                    categoryCode = idCategoryCodeMap[id];
                    bool loadsucc = loadedCompnentService->LoadComponentIntoProject(pDoc,name, uniqueName, categoryCode, true);
                    retLoadResultMap.emplace(id, loadsucc);
                    DBG_WARN_AND_CONTINUE_UNLESS(loadsucc, L"加载族失败："+ name, L"GMEP", L"2024-01-30");
                    ++succCount;
                }
                else
                {
                    retLoadResultMap.emplace(id, false);
                    DBG_WARN(L"下载该族信息失败：" + name, L"GMEP", L"2024-01-30");
                }

                
            }
        }
        if (pViewOptions != nullptr)
            pViewOptions->ReportProgress(GBMP_TR(L"正在载入"), 1.0f);
        return retLoadResultMap;
    }

  
    //单机版
    bool GmepLocalComponentOpertions::LoadOnePublicComponent(const std::wstring &id, const std::wstring &name, const std::wstring &version, gcs::IGcsViewOptions *pViewOptions,
        std::wstring &strUniqueName, std::wstring& strCategoryCode, bool &bSkipped)
    {
        bSkipped = false;
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pViewOptions, L"pViewOptions为空", L"GMEP", L"2024-01-30");
        pViewOptions->ReportProgress(GBMP_TR(L"正在载入"));

        // 1. 设置默认输出值
        strUniqueName = name;
        strCategoryCode = L"";

        // 2. 获取当前文档
        gcmp::IDocument* pDoc = AppService::GetCurrentDocument();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc != nullptr, L"pDoc为空", L"GMEP", L"2024-01-30");

        // 3. 检查是否已载入
        gmepgcs::ProjectLoadedComponentService* pLoadService = gmepgcs::ProjectLoadedComponentService::Get();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pLoadService != nullptr, L"pLoadService为空", L"GMEP", L"2024-01-30");

        bool isLoaded = pLoadService->CheckFamilyExistByIdAndName(pDoc, id, name);
        if (isLoaded)
        {            
            EDuplicateChoice userChoice = PopUpDuplicateWarning(pViewOptions, true); // messageBox, 取消，跳过，还是存为副本 （1）
            if (userChoice != EDuplicateChoice::Continue)
            {
                if (userChoice == EDuplicateChoice::Skip)
                {
                    bSkipped = true;
                }
                return false;
            }
        }

        // 4. 构造文档中唯一不重复的族名称，用以载入
        strUniqueName = pLoadService->GetUniqueFamilyName(pDoc, name);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(!strUniqueName.empty(), L"strUniqueName为空", L"GMEP", L"2024-01-30");

        // 5. 同步到本地并载入文档
        std::vector<std::tuple<std::wstring, std::wstring, std::wstring>> idNameUniqueNameVec;
        std::map<std::wstring, std::wstring> idNameMap; // db3 里id 和name
        idNameUniqueNameVec.emplace_back(std::make_tuple(id, name, strUniqueName));
        idNameMap.emplace(id, name);        
        std::map<std::wstring, std::wstring> idCategoryCodeMap;
        std::map<std::wstring, bool> retLoadResultMap = SyncAndLoadPublicComponents(pDoc, idNameUniqueNameVec, idNameMap, version, nullptr, idCategoryCodeMap);
        if (retLoadResultMap.empty() || retLoadResultMap.begin()->second == false || idCategoryCodeMap.empty())
        {
            pViewOptions->ReportFailure(GBMP_TR(L"载入失败"));
            return false;
        }

        strCategoryCode = idCategoryCodeMap.begin()->second;        
        pViewOptions->ReportSuccess(GBMP_TR(L"载入成功"));
        return true;
    }

    //单机版
    std::map<std::wstring, bool> GmepLocalComponentOpertions::LoadInBatchPublicComponents(const std::map<std::wstring, std::wstring> &idNames, const std::wstring &version, const std::shared_ptr<gcs::IGcsViewOptions> &spViewOptions)
    {
        std::map<std::wstring, bool> retLoadResultMap;
        DBG_WARN_AND_RETURN_UNLESS(spViewOptions, retLoadResultMap,  L"spViewOptions为空", L"GMEP", L"2024-01-30");
        spViewOptions->ReportProgress(GBMP_TR(L"正在载入"), 0.0f);

        // 1. 获取当前文档
        gcmp::IDocument* pDoc = AppService::GetCurrentDocument();
        DBG_WARN_AND_RETURN_UNLESS(pDoc != nullptr, retLoadResultMap, L"pDoc为空", L"GMEP", L"2024-01-30");

        // 2. 准备数据
        gmepgcs::ProjectLoadedComponentService* pLoadService = gmepgcs::ProjectLoadedComponentService::Get();
        DBG_WARN_AND_RETURN_UNLESS(pLoadService != nullptr, retLoadResultMap, L"pLoadService为空", L"GMEP", L"2024-01-30");

        std::vector<std::tuple<std::wstring, std::wstring, std::wstring>> idNameUniqueNameVec;
        std::map<std::wstring, std::wstring> idNameMap; // db3 里id 和name
        bool bSkipLoaded = false;
        bool hasPopUpWarning = false; // 仅弹警告一次
        for (auto& idName : idNames)
        {
            // 2.1 检查是否已载入
            bool isLoaded = pLoadService->CheckFamilyExistByIdAndName(pDoc, idName.first, idName.second);
            if (isLoaded)
            {
                if (!hasPopUpWarning) // 用户未做过选择
                {
                    hasPopUpWarning = true;                                       
                    EDuplicateChoice userChoice = PopUpDuplicateWarning(spViewOptions.get(), false); // messageBox, 取消，跳过，还是存为副本 （1）
                    if (userChoice == EDuplicateChoice::Cancel) // 若取消, 则取消整个批量载入过程
                    {
                        return retLoadResultMap;
                    }
                    
                    if (userChoice == EDuplicateChoice::Skip) // 若跳过, 则跳过当前并记住选择，下次不再提示
                    {
                        bSkipLoaded = true;
                        continue;
                    }
                }

                if (bSkipLoaded) // 用户此前已选择跳过
                {
                    continue;
                }
            }

            // 2.2 构造文档中唯一不重复的族名称，用以载入
            std::wstring strUniqueName = pLoadService->GetUniqueFamilyName(pDoc, idName.second);
            DBG_WARN_AND_CONTINUE_UNLESS(!strUniqueName.empty(), L"strUniqueName为空", L"GMEP", L"2024-01-30");
            idNameUniqueNameVec.emplace_back(std::make_tuple(idName.first, idName.second, strUniqueName));
            idNameMap.emplace(idName);
        }

        if (idNameMap.empty()) // 全部被跳过了
        {
            return retLoadResultMap;
        }

        // 3. 同步到本地并载入文档
        std::map<std::wstring, std::wstring> idCategoryCodeMap;
        retLoadResultMap = SyncAndLoadPublicComponents(pDoc, idNameUniqueNameVec, idNameMap, version, spViewOptions.get(), idCategoryCodeMap);
        
        // 4. 汇报结果
        size_t totalCount = idNameMap.size();
        size_t successCount = 0;
        size_t failureCount = 0;
        for (auto &resultItem : retLoadResultMap)
        {
            if (resultItem.second)
            {
                successCount++;
            }
            else
            {
                failureCount++;
            }
        }

        if (successCount == totalCount)
        {
            spViewOptions->ReportSuccess(GBMP_TR(L"载入成功"));
            return retLoadResultMap;
        }

        gcs::MessageAction okAction(L"Ok"); okAction.DisplayText = GBMP_TR(L"确定"); okAction.IsSolid = true;
        std::wstring message = failureCount == totalCount ? GBMP_TR(L"全部载入失败") : GBMP_TR(L"部分构件载入失败");
        spViewOptions->ShowMessageBox(L"", message, gcs::EMessageType::Warning, { okAction });
        return retLoadResultMap;
    }

    // 已添加 的标记
    std::unordered_map<std::wstring, bool> GmepLocalComponentDataProvider::CheckComponentLoaded(gcs::EGcsEdition edition, const std::vector<std::shared_ptr<gcs::IComponentDto>> &components) const
    {
        std::unordered_map<std::wstring, bool> retMap;
        if (components.size() == 0)
            return retMap;

        std::vector<std::wstring> componentIds;
        FOR_EACH(item, components)
        {
            DBG_WARN_AND_CONTINUE_UNLESS(item!= nullptr, L"components存在空成员", L"GMEP", L"2024-01-30");

            std::wstring strId = item->Id();
            componentIds.emplace_back(strId);
        }

        // 单机版检查此文档是否已经有此公共库id的族载入了
        if (edition == gcs::EGcsEdition::Standalone)
        {
            gcmp::IDocument* pDoc = AppService::GetCurrentDocument();
            gmepgcs::ProjectLoadedComponentService* pLoadService = gmepgcs::ProjectLoadedComponentService::Get();

            DBG_WARN_AND_RETURN_UNLESS(pDoc != nullptr && pLoadService != nullptr, retMap, L"pLoadService为空", L"GMEP", L"2024-01-30");

            for (auto& spComponentDto : components)
            {
                if (!spComponentDto)
                {
                    continue;
                }

                bool bLoaded = pLoadService->CheckFamilyExistByIdAndName(AppService::GetCurrentDocument(), spComponentDto->Id(), spComponentDto->Name());
                retMap.emplace(spComponentDto->Id(), bLoaded);
            }
        }
        else // 协同版query 云端接口，是否已经添加此构件
        {
            gmepgcs::ProjectCloudComponentService* pCloudService = gmepgcs::ProjectCloudComponentService::Get();
            DBG_WARN_AND_RETURN_UNLESS(pCloudService != nullptr, retMap, L"pCloudService为空", L"GMEP", L"2024-01-30");

            IProjectManager* pProjectManager = IProjectManager::Get();
            DBG_WARN_AND_RETURN_UNLESS(pProjectManager != nullptr, retMap, L"pProjectManager为空", L"GMEP", L"2024-01-30");

            std::shared_ptr<PublicComponentAddedCheck> spPublicComponentAddedCheck = std::make_shared<PublicComponentAddedCheck>();
            DBG_WARN_AND_RETURN_UNLESS(spPublicComponentAddedCheck, retMap, L"spPublicComponentAddedCheck为空", L"GMEP", L"2024-01-30");

            spPublicComponentAddedCheck->ProjectId = pProjectManager->GetCurrentProjectId();
            for (auto& spComponentDto : components)
            {
                if (!spComponentDto)
                {
                    continue;
                }

                std::shared_ptr<PublicComponentDto> spPublicComponentDto = ConvertToPublicComponentDto(spComponentDto);
                if (!spPublicComponentDto)
                {
                    continue;
                }

                spPublicComponentAddedCheck->PublicComponents.push_back(spPublicComponentDto);
            }

            std::vector<std::shared_ptr<PublicComponentAddedCheckResult>> publicComponentAddedCheckResults = pCloudService->CheckPublicComponentAdded(spPublicComponentAddedCheck);
            for (auto &spResult : publicComponentAddedCheckResults)
            {
                if (!spResult)
                {
                    continue;
                }

                retMap.emplace(spResult->PublicComponentId, spResult->Exist);
            }
        }

        return retMap;
    }
}